#pragma once
#ifndef __USER_DRAG__INCLUDED__HH__
#define __USER_DRAG__INCLUDED__HH__

#include <qpoint.h>
#include <qrect.h>
#include <qsize.h>
#include <qrubberband.h>
#include <boost\function.hpp>
#include <LitPointer.hpp>
#include <LitPrerequisites.h>
#include <LitFlags.hpp>

enum UserDragFlag
{
	// Drag delta since last frame
	UDF_FRAME_DELTA = 1<<1,
	// Drag delta from mouse press to mouse release
	UDF_BUTTON_RELEASE_DELTA = 1<<2,
	// Drag delta from mouse press to mouse release
	UDF_NO_RUBBER_BAND = 1<<3
};

typedef Lit::Flags<UserDragFlag>	UserDragFlags;

enum UserDragButton
{
	UDB_NONE = 0,
	UDB_LEFT = 1<<1,
	UDB_MIDDLE = 1<<2,
	UDB_RIGHT = 1<<3
};

enum UserDragEvent
{
	UDE_INIT,
	UDE_UPDATE,
	UDE_STOP
};

class UserDrag
{
public:
	typedef QPoint						PointType;
	typedef UserDragFlags				DragFlags;
	typedef QRubberBand					RubberBandType;
	typedef UserDragButton				ButtonType;
	typedef Lit::Vec2					FloatPointType;
	typedef QRect						RectType;
	typedef QSize						SizeType;
	/*
		const Flags<UserDragFlags>&	drag flags, 
		UserDragButton				drag button, 
		const Point&				starting point, 
		const Point&				ending point
	*/
	typedef boost::function<void( UserDragEvent evt, Lit::RefPtr<UserDrag> drag )> CallbackType;

protected:
	bool							mDrag;
	PointType						mDragStart;
	PointType						mDragEnd;
	RubberBandType *				mBand;
	DragFlags						mFlags;
	ButtonType						mButton;

	CallbackType					mCallback;
	static void _callbackDummy( UserDragEvent evt, Lit::RefPtr<UserDrag> drag ){}
public:
	static Lit::Vec2 mouseWidgetRatio( QPoint localpos, QRect geometry );

	UserDrag( QWidget*widget, DragFlags flags = UDF_BUTTON_RELEASE_DELTA, CallbackType call_back = &UserDrag::_callbackDummy );
	UserDrag( const UserDrag& rhs );
	~UserDrag();

	bool isFrameDelta() const;
	bool isButtonReleaseDelta() const;
	UserDrag& operator=( const UserDrag& rhs );

	ButtonType				button()					const;
	bool					isDragging()				const;
	
	bool					hasRubberBand()				const;
	const DragFlags	&		flags()						const;
	DragFlags	&			flags();

	const PointType&		start()						const;
	const PointType&		end()						const;

	RubberBandType*			rubberBand();
	const RubberBandType*	rubberBand()				const;

	SizeType				dragSize()					const;
	RectType				dragRect()					const;
	PointType				delta()						const;
	FloatPointType			deltaFactor( float factor ) const;

	bool					draggedAtLeast( const SizeType& sz ) const;

	bool operator == ( const UserDrag& rhs ) const;
	bool operator != ( const UserDrag& rhs ) const;

	bool operator > ( const UserDrag& rhs ) const;
	bool operator < ( const UserDrag& rhs ) const;
	bool operator >= ( const UserDrag& rhs ) const;
	bool operator <= ( const UserDrag& rhs ) const;

	bool operator > ( const SizeType& rhs ) const;
	bool operator < ( const SizeType& rhs ) const;
	bool operator >= ( const SizeType& rhs ) const;
	bool operator <= ( const SizeType& rhs ) const;

	void initDrag( const PointType& start_point, ButtonType btn = UDB_LEFT );
	void updateDrag( const PointType& curr_pos, bool force_update =false );
	void closeDrag( const PointType& end_pos );
};
typedef Lit::RefPtr<UserDrag> UserDragPtr;

#endif